﻿using InternetSpiderLib;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml;

namespace VerticalSpiderEditor
{
    public partial class Form1 : Form
    {
        private XmlDocument _XmlDocument = new XmlDocument();

        private string CacheFile = "__cache.xml";

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            if (File.Exists(CacheFile))
            {
                _XmlDocument.Load(CacheFile);
            }
            else
            {
                InitXmlDocument();
            }

            XmlDocumentTreeViewMapping.BuildTreeViewByXml(_XmlDocument, treeView1);
            treeView1.ExpandAll();
        }

        private void InitXmlDocument()
        {
            var netspider = _XmlDocument.AddChildNode("NetSpider");

            netspider.AddChildNode("Dependent");
            netspider.AddChildNode("SpiderVariable");
            netspider.AddChildNode("Spiders");
        }

        private void Button_Load_Click(object sender, EventArgs e)
        {
            OpenFileDialog dialog = new OpenFileDialog();
            if (dialog.ShowDialog() == DialogResult.OK)
            {
                BindXmlFileToTreeView(dialog.FileName);
            }
        }

        private void BindXmlFileToTreeView(string xmlfile)
        {
            _XmlDocument.Load(xmlfile);

            XmlDocumentTreeViewMapping.BuildTreeViewByXml(_XmlDocument, treeView1);
            treeView1.ExpandAll();
        }

        private void Button_Save_Click(object sender, EventArgs e)
        {
            SaveFileDialog dialog = new SaveFileDialog();
            if (dialog.ShowDialog() == DialogResult.OK)
            {
                _XmlDocument.Save(dialog.FileName);
            }
        }

        private string GetXPathFormTree()
        {
            return XmlDocumentTreeViewMapping.GetXPathFormTree(treeView1);
        }

        private void TreeView1_AfterSelect(object sender, TreeViewEventArgs e)
        {
            //var path = GetXPathFormTree();
            //this.Text = path;

            var contols = GetShowControls(_XmlDocument, GetXPathFormTree());
            groupBox_Attribute.Controls.Clear();

            if (contols != null)
            {
                for (int i = 0; i < contols.Count; ++i)
                {
                    var item = contols[i];
                    var label = new Label { Text = item.Key };
                    var controlValue = item.Value;

                    groupBox_Attribute.Controls.Add(label);
                    groupBox_Attribute.Controls.Add(controlValue);

                    label.Width = 100;
                    label.BackColor = Color.Green;
                    label.TextAlign = ContentAlignment.MiddleRight;

                    controlValue.Width = groupBox_Attribute.Width - 50 - label.Width;
                    controlValue.Name = item.Key;

                    label.Location = new Point(20, 30 * i + 20);
                    controlValue.Location = new Point(130, 30 * i + 20);
                }
            }
        }

        private List<KeyValuePair<string, Control>> GetShowControls(XmlDocument document, string xpath)
        {
            var node = document.SelectSingleNode(xpath);
            if (node == null)
                return null;

            if (xpath == "/NetSpider/Dependent")
            {
                return new List<KeyValuePair<string, Control>>
                {
                    GetSelectControl("Item", new List<string>
                    {
                        "InternetSpiderLib"
                    }),
                };
            }

            if (Regex.Match(xpath, $"^/NetSpider/Dependent\\[[\\d]+?\\]$").Success)
            {
                return GetTextControls("Item", node.InnerText);
            }

            if (xpath == "/NetSpider/SpiderVariable")
            {
                return GetTextControls(
                    "Name", "",
                    "Value", "");
            }

            if (Regex.Match(xpath, $"^/NetSpider/SpiderVariable/Item\\[[\\d]+?\\]$").Success)
            {
                return GetTextControls(
                    "Name", node.SelectSingleNode("./Name").InnerText,
                    "Value", node.SelectSingleNode("./Value").InnerText);
            }

            if (xpath == "/NetSpider/Spiders")
            {
                var list = new List<KeyValuePair<string, Control>>();
                list.Add(GetSelectControl("Type", VerticalSpiderXmlHelper.GetCoincidentalTypeNames(typeof(NetSpider))));
                return list;
            }

            if (node.Name == "Item")
            {
                var typeName = node.SelectSingleNode("./Type")?.InnerText;
                if (string.IsNullOrEmpty(typeName) == false)
                {
                    var type = Type.GetType(typeName);

                    if (type != null)
                    {
                        if (type.IsArray)
                            return null;

                        List<KeyValuePair<string, Control>> controls = new List<KeyValuePair<string, Control>>();

                        foreach (var itemProperty in type.GetProperties())
                        {
                            var propertyNode = node.SelectSingleNode($"./Property/Item[Name='{itemProperty.Name}']");
                            var control = GetControlByType(itemProperty.PropertyType, propertyNode);
                            if (control != null)
                            {
                                controls.Add(new KeyValuePair<string, Control>(itemProperty.Name, control));
                            }
                        }

                        return controls;
                    }
                }
            }

            if (node.Name == "List")
            {
                var listTypeName = node.ParentNode?.SelectSingleNode("./Type")?.InnerText;
                var listType = Type.GetType(listTypeName);
                var elementType = listType.GetElementType();

                var list = new List<KeyValuePair<string, Control>>();

                if (elementType.IsEnum)
                {
                    var array = Enum.GetValues(elementType);
                    var combobox = new ComboBox();

                    foreach (var item in array)
                    {
                        combobox.Items.Add(item.ToString());
                    }
                    list.Add(new KeyValuePair<string, Control>("Item", combobox));
                }
                else if (elementType == typeof(string) || elementType.IsValueType)
                {
                    list.AddRange(GetTextControls("Item", ""));
                }
                else
                {
                    list.Add(GetSelectControl("Type", VerticalSpiderXmlHelper.GetCoincidentalTypeNames(elementType)));
                }
                return list;
            }

            return null;
        }

        private Control GetControlByType(Type type, XmlNode propertyNode)
        {
            if (type == typeof(string))
            {
                return new TextBox()
                {
                    Text = propertyNode?.SelectSingleNode("./Value")?.InnerText,
                };
            }

            if (type.IsEnum)
            {
                var array = Enum.GetValues(type);
                var combobox = new ComboBox();

                foreach (var item in array)
                {
                    combobox.Items.Add(item.ToString());
                }

                var value = propertyNode?.SelectSingleNode("./Value")?.InnerText;
                combobox.Text = value;

                return combobox;
            }

            if (type.IsValueType)
            {
                return new TextBox
                {
                    Text = propertyNode?.SelectSingleNode("./Value")?.InnerText
                };
            }

            if (type.IsArray)
            {
                var combobox = new ComboBox();

                combobox.Items.Add(TypeHelper.GetTypeFullName(type));

                var value = propertyNode?.SelectSingleNode("./Type")?.InnerText;
                combobox.Text = value;

                return combobox;
            }

            if (type.IsClass || type.IsInterface)
            {
                var array = VerticalSpiderXmlHelper.GetCoincidentalTypeNames(type);
                var combobox = new ComboBox();

                foreach (var item in array)
                {
                    combobox.Items.Add(item.ToString());
                }

                var value = propertyNode?.SelectSingleNode("./Type")?.InnerText;
                combobox.Text = value;

                return combobox;
            }

            return null;
        }

        private List<KeyValuePair<string, Control>> GetTextControls(params string[] items)
        {
            if (items.Length % 2 != 0)
                throw new Exception("传入了不匹配的参数");

            List<KeyValuePair<string, Control>> controls = new List<KeyValuePair<string, Control>>();

            for (int i = 0; i < items.Length / 2; i++)
            {
                var key = items[i * 2];
                var value = items[i * 2 + 1];

                controls.Add(new KeyValuePair<string, Control>(key, new TextBox { Text = value }));
            }

            return controls;
        }

        private KeyValuePair<string, Control> GetSelectControl(string name, List<string> values)
        {
            ComboBox comboBox = new ComboBox();
            comboBox.DropDownStyle = ComboBoxStyle.DropDownList;

            foreach (var item in values)
            {
                comboBox.Items.Add(item);
            }

            return new KeyValuePair<string, Control>(name, comboBox);
        }

        private void Button_AddAttribute_Click(object sender, EventArgs e)
        {
            List<KeyValuePair<string, string>> values = new List<KeyValuePair<string, string>>();

            foreach (var item in groupBox_Attribute.Controls)
            {
                if (item is Label)
                    continue;

                if (item is TextBox)
                {
                    var textbox = item as TextBox;
                    if (string.IsNullOrEmpty(textbox.Text) == false)
                        values.Add(new KeyValuePair<string, string>(textbox.Name, textbox.Text));
                }

                if (item is ComboBox)
                {
                    ComboBox comboBox = item as ComboBox;
                    if (string.IsNullOrEmpty(comboBox.Text) == false)
                        values.Add(new KeyValuePair<string, string>(comboBox.Name, comboBox.Text));
                }
            }

            var xpath = GetXPathFormTree();
            XmlDocumentTreeViewMapping.SaveToDocument(_XmlDocument, xpath, values);

            XmlDocumentTreeViewMapping.BuildTreeViewByXml(_XmlDocument, treeView1);
            treeView1.ExpandAll();

            XmlDocumentTreeViewMapping.SelectNodeByXPath(treeView1, xpath);
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            _XmlDocument.Save(CacheFile);
        }

        private void Button_ClearCache_Click(object sender, EventArgs e)
        {
            _XmlDocument.RemoveAll();
            InitXmlDocument();

            XmlDocumentTreeViewMapping.BuildTreeViewByXml(_XmlDocument, treeView1);
            treeView1.ExpandAll();
        }

        private void Button_DeleteNode_Click(object sender, EventArgs e)
        {
            var xpath = GetXPathFormTree();
            var node = _XmlDocument.SelectSingleNode(xpath);
            if (node != null)
                node.ParentNode.RemoveChild(node);

            XmlDocumentTreeViewMapping.BuildTreeViewByXml(_XmlDocument, treeView1);
            treeView1.ExpandAll();
        }
    }
}
